﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing;
using System.IO;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using InterpriseSuiteEcommerceCommon.Extensions;

namespace InterpriseSuiteEcommerceCommon.Tool
{
    public static class ImageHelper
    {
        public static long GetSize(Stream fileStream) 
        {
            try
            {
                return fileStream.Length;
            }
            catch (Exception)
            {
                throw;
            }
        }

        public static void ResizeCustomImage(System.Drawing.Image origPhoto, string newImg_fName, int width, int height)
        {
            int resizedWidth = width;
            int resizedHeight = height;
            int sourceWidth = origPhoto.Width;
            int sourceHeight = origPhoto.Height;

            int sourceX = 0;
            int sourceY = 0;
            int destX = -2;
            int destY = -2;
            float nPercent = 0;
            float nPercentW = ((float)resizedWidth / (float)sourceWidth);
            float nPercentH = ((float)resizedHeight / (float)sourceHeight);
            int destWidth = 0;
            int destHeight = 0;

            if (nPercentH < nPercentW)
            {
                nPercent = nPercentW;
                destY = (int)((resizedHeight - (sourceHeight * nPercent)) / 2) - 2;
            }
            else
            {
                nPercent = nPercentH;
                destX = (int)((resizedWidth - (sourceWidth * nPercent)) / 2) - 2;
            }

            destWidth = (int)Math.Ceiling(sourceWidth * nPercent) + 4;
            destHeight = (int)Math.Ceiling(sourceHeight * nPercent) + 4;

            var resizedPhoto = new Bitmap(resizedWidth, resizedHeight, PixelFormat.Format24bppRgb);

            var grPhoto = Graphics.FromImage(resizedPhoto);
            grPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic;
            grPhoto.DrawImage(origPhoto,
                new Rectangle(destX, destY, destWidth, destHeight),
                new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),
                GraphicsUnit.Pixel);

            grPhoto.Dispose();
            origPhoto.Dispose();
            resizedPhoto.Save(newImg_fName);
            resizedPhoto.Dispose();
        }

        public static ImageFormat GetContentType(byte[] imageBytes)
        {
            var ms = new MemoryStream(imageBytes);
            using (var br = new BinaryReader(ms))
            {
                int maxMagicBytesLength = imageFormatDecoders.Keys.OrderByDescending(x => x.Length).First().Length;

                byte[] magicBytes = new byte[maxMagicBytesLength];

                for (int i = 0; i < maxMagicBytesLength; i += 1)
                {
                    magicBytes[i] = br.ReadByte();

                    foreach (var kvPair in imageFormatDecoders)
                    {
                        if (magicBytes.ToString().StartsWith(kvPair.Key.ToString()))
                        {
                            return kvPair.Value;
                        }
                    }
                }
                throw new ArgumentException("Could not recognise image format", "binaryReader");
            }
        }

        private static bool StartsWith(this byte[] thisBytes, byte[] thatBytes)
        {
            for (int i = 0; i < thatBytes.Length; i += 1)
            {
                if (thisBytes[i] != thatBytes[i]) { return false; }
            }
            return true;
        }

        public static byte[] ReadFully(Stream input)
        {
            using (var ms = new MemoryStream())
            {
                input.CopyTo(ms);
                return ms.ToArray();
            }
        }

        public static string GetContentTypeValue(ImageFormat format)
        { 
            string content = string.Empty;
            if (format.Guid == System.Drawing.Imaging.ImageFormat.Bmp.Guid)
                content = "image/x-ms-bmp";
            else if (format.Guid == System.Drawing.Imaging.ImageFormat.Jpeg.Guid)
                content = "image/jpeg";
            else if (format.Guid == System.Drawing.Imaging.ImageFormat.Gif.Guid)
                content = "image/gif";
            else if (format.Guid == System.Drawing.Imaging.ImageFormat.Png.Guid)
                content = "image/png";
            else content = "application/octet-stream";
            return content;
        }

        public static string GetProperExtensions(Stream fileStream, string mime)
        {
            string contentType = GetContentTypeValue(GetContentType(ReadFully(fileStream)));
            string mimeExtension = ".{0}".FormatWith(mime);
            switch (contentType)
            {
                case "image/x-ms-bmp":
                    return mimeExtension;
                case "image/jpg":
                case "image/jpeg":
                case "image/pjpeg":
                    return ".jpg";
                case "image/gif":
                    return ".gif";
                case "image/x-png":
                case "image/png":
                    return ".png";
                default:
                    return mimeExtension;
            }
        }

        public static Image ScaleByPercent(Image imgPhoto, int Percent)
        {
            float nPercent = ((float)Percent / 100);

            int sourceWidth = imgPhoto.Width;
            int sourceHeight = imgPhoto.Height;
            int sourceX = 0;
            int sourceY = 0;

            int destX = 0;
            int destY = 0;
            int destWidth = (int)(sourceWidth * nPercent);
            int destHeight = (int)(sourceHeight * nPercent);

            var bmPhoto = new Bitmap(destWidth, destHeight, PixelFormat.Format24bppRgb);
            bmPhoto.SetResolution(imgPhoto.HorizontalResolution, imgPhoto.VerticalResolution);

            var grPhoto = Graphics.FromImage(bmPhoto);
            grPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic;

            grPhoto.DrawImage(imgPhoto, 
                                new Rectangle(destX, destY, destWidth, destHeight),
                                new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),
                                GraphicsUnit.Pixel);

            grPhoto.Dispose();
            return bmPhoto;
        }

        private static Dictionary<byte[], ImageFormat> imageFormatDecoders = new Dictionary<byte[], ImageFormat>()
        {
            { new byte[]{ 0x42, 0x4D }, ImageFormat.Bmp},
            { new byte[]{ 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 }, ImageFormat.Gif },
            { new byte[]{ 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 }, ImageFormat.Gif },
            { new byte[]{ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }, ImageFormat.Png },
            { new byte[]{ 0xff, 0xd8 }, ImageFormat.Jpeg },
        };

        public static int GetPercentage(long size)
        {
            int percentage = 90;
            float megs = size / 1000;
            if (megs >= 2) { percentage = 50; }
            if (megs < 2) { percentage = 90; }
            if (megs <= 1) { percentage = 95; }

            return percentage;
        }

        public static void OptimizeAndSaveImage(Stream picStream, string trueFileName, long pictureLimit)
        {
            long size = GetSize(picStream) / 1000;
            int percentage = GetPercentage(size);

            if (size > pictureLimit)
            {
                while (true)
                {
                    if (size > pictureLimit)
                    {
                        try
                        {
                            var scaledImage = ScaleByPercent(Image.FromStream(picStream), percentage);
                            picStream.Close();
                            picStream.Dispose();

                            scaledImage.Save(trueFileName);
                            scaledImage.Dispose();

                            picStream = new FileStream(trueFileName, FileMode.OpenOrCreate);
                            size = picStream.Length / 1000;

                            percentage = ImageHelper.GetPercentage(size);
                        }
                        catch (Exception)
                        {
                            throw;
                        }
                    }
                    else
                    {
                        picStream.Close();
                        picStream.Dispose();
                        break;
                    }
                }
            }
            else
            {
                var fileInfo = new FileInfo(trueFileName);
                if (fileInfo.Exists) fileInfo.Delete();

                var img = Image.FromStream(picStream);
                img.Save(trueFileName);
                img.Dispose();
            }
        }
    }
}